<?php
/**
 * XGPHP 轻量级PHP框架
 * @link http://xgphp.xg3.cn
 * @version 1.2.0
 * @license http://www.apache.org/licenses/LICENSE-2.0
 * @author 讯高科技 <xungaokeji@qq.com>
*/
namespace xg;

use \helper\Arr;
use \helper\Str;
use \helper\Checker;

class Hook {
	protected $default=null;
	protected $name=null;
	protected $once=false;
	protected $data=[];
	protected static $hooks=[];
 	public function __construct($name){
		$this->name=$name;
	}
	static public function hook($name,$callable){
        static::$hooks = Arr::set(static::$hooks,$name,$callable);
	}
	static public function create($name){
		return new static($name);
	}
	public function once(){
		$this->once=true;
		$args=func_get_args();
		return $this->exec($args);
	}
	public function run(){
		$args=func_get_args();
		return $this->exec($args);
	}
	public function _default($default){
		$this->default=$default;
		return $this;
	}
	public function data(){
		return $this->data;
	}
	public function last(){
		if(count($data=$this->data)){
            return end(array_values($data));
        }
		return $this->default;
	}
	protected function exec(array $args){
		$hooks=Arr::get(static::$hooks,$this->name);
		$fullName = $this->name;
		$name = end(Arr::split($this->name,'.'));
        $result = null;
        if($hooks) {
			$_args = $args;
			$_args[] = $this;
            foreach($hooks as $key=>$callable) {
                if(Checker::isClosure($callable)){
					$closure = \Closure::bind($callable, $this);
                    $result = call_user_func_array($closure,$_args);
                }elseif(Checker::isCallable($callable)){
                    $result = call_user_func_array($callable,$_args);
                }elseif(is_array($callable)){
                    foreach($callable as $_callable){
                        if(Checker::isCallable($_callable)){
                            $result = call_user_func_array($_callable,$_args);
                        }elseif(Checker::isClosure($_callable)){
							$closure = \Closure::bind($_callable, $this);
							$result = call_user_func_array($closure,$_args);
						}elseif(is_object($_callable) or class_exists($_callable)){
							if(is_object($_callable)){
								$obj=$_callable;
							}else{
								$obj=new $_callable();
							}
							$methodName = Str::camel($name);
							$fullMethodName = Str::camel(str_replace('.','_',$fullName));
                            if(method_exists($obj,$methodName)){
                                $result=call_user_func_array([$obj,$methodName],$_args);
                            }elseif($fullMethodName!=$methodName and method_exists($obj,$fullMethodName)){
                                $result=call_user_func_array([$obj,$fullMethodName],$_args);
							}
                        }
                    }
                }elseif(is_object($callable) or class_exists($callable)){
					if(is_object($callable)){
						$obj=$callable;
					}else{
						$obj=new $callable();
					}
					$methodName = Str::camel($name);
					$fullMethodName = Str::camel(str_replace('.','_',$fullName));
					if(method_exists($obj,$methodName)){
						$result=call_user_func_array([$obj,$methodName],$_args);
					}elseif($fullMethodName!=$methodName and method_exists($obj,$fullMethodName)){
						$result=call_user_func_array([$obj,$fullMethodName],$_args);
					}
				}
                if(!is_null($result)){
                    $this->data[$key]=$result;
                    if($this->once){
                        return $this;
                    }
                }
            }
        }
		return $this;
	}
	function __call($method,$params){
		if($method==='default'){
			return call_user_func_array([$this,'_default'],$params);
		}
	}
}
?>